package server;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Vector;

import shared.Vec2f;
import shared.Vec2i;
import vmo.Actor;
import vmo.Chunk;
import vmo.Collision_Interface;
import vmo.Tile;

public class Entity implements Collision_Interface{

	public enum EntityType{WORLD,STATIC,SHIP};
//worlds are planets, they have cores, statics are immobile objects without cores, ships are mobile objects
	//cores mean that A. the world wraps around east to west B. you can't move further south or north than the edge
	//C. they have tiles all the way to the edge of the grid on at least some level
	//on a static or ship moving off the edge sets you adrift in the world
	public EntityType m_type;
	public Chunk [][] m_chunks;
	public short m_width,m_height;
	public float m_mass;
	public Vec2f m_position,m_velocity;
	public boolean m_loaded;
	public Vector<Actor> m_actors;
	String m_id; //a name needed to find the thing later
	
	public Entity(Vec2f pos, String ID)
	{
		m_id=ID;
		m_position=pos;
		m_velocity=new Vec2f(0,0);
		m_actors=new Vector <Actor>();	
	}
	
	public Entity(String ID)
	{
		m_id=ID;
		m_actors=new Vector <Actor>();		
	}
	
	public boolean Save() throws IOException
	{
		String str="save/"+m_id+".ent";
		File file=new File(str);
		file.createNewFile();
		
		FileOutputStream fstream;
		DataOutputStream dstream;
		try {
			fstream= new FileOutputStream(file,false);
			dstream= new DataOutputStream(fstream);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			
			e.printStackTrace();
			return false;
		}
		//write type
		dstream.write(getTypeByte(m_type));
		//write position
		m_position.Save(dstream);
		m_velocity.Save(dstream);
		//write size
		dstream.writeShort(m_width);
		dstream.writeShort(m_height);
		//write chunks
		for (int i=0;i<m_width;i++)
		{
			for (int j=0;j<m_height;j++)
			{
				m_chunks[i][j].Save(dstream);
			}
		}
		return true;
	}
	
	public boolean Load() throws IOException
	{
		String str="save/"+m_id+".ent";
		FileInputStream fstream;
		DataInputStream dstream;	
		try {
			fstream= new FileInputStream(str);
			dstream= new DataInputStream(fstream);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}		
		//read type
		m_type=Entity.getTypefromByte(dstream.readByte());
		//read position
		m_position=new Vec2f(dstream);
		m_velocity=new Vec2f(dstream);
		//read size
		m_width=dstream.readShort();
		m_height=dstream.readShort();
		
		m_chunks=new Chunk[m_width][];
		for (int i=0;i<m_width;i++)
		{
			m_chunks[i]=new Chunk[m_height];
			for (int j=0;j<m_height;j++)
			{
				m_chunks[i][j]=new Chunk(dstream);
			}
		}
		return true;
	}
	
	public static Entity LoadEntity(String string)
	{
		Entity entity=new Entity(string);
		try {
			if (entity.Load())
			{
				return entity;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	static public byte getTypeByte(EntityType type)
	{
		switch (type)
		{
		case WORLD:
			return 0;
		case STATIC:
			return 1;
		case SHIP:
			return 2;
		}
		return 0;
	}
	
	static public EntityType getTypefromByte(byte b)
	{
		switch (b)
		{
		case 0:
			return EntityType.WORLD;
		case 1:
			return EntityType.STATIC;
		case 2:
			return EntityType.SHIP;
		
		}
		return EntityType.WORLD;
	}
	
	public void WorldGenerator(short width, short height)
	{
		m_type=EntityType.WORLD;
		m_width=width;
		m_height=height;
		//generate grid
		m_chunks=Generators.WorldGenerator0(width, height);
		
		
	}

	public void AddActor(Actor actor)
	{
		actor.m_interface=this;
		m_actors.add(actor);
		
		
	}
	
	@Override
	public Tile getTile(float x, float y, byte layer) {
		// TODO Auto-generated method stub
		//if out of bounds report tiletype as bounds
		if (x<0 || x>m_width*16)
		{
			return null;
		}
		if (y<0 || y>m_height*16)
		{
			return null;
		}	
		int xe=(int) (x/16), ye=(int) (y/16);
		Vec2i vi=new Vec2i(xe,ye);
		//dont need to client coordinates, coordinates in entity space are fixed
		Chunk c=m_chunks[vi.x][vi.y];
		if (c!=null)
		{
			int xc=(int) (x%16);
			int yc=(int) (y%16);
			if (c.m_tiles[layer]!=null)
			{
				return c.m_tiles[layer][xc][yc];              
			}
		}
		return null;
	}
	
	void Update(float dt,boolean save)
	{
		if (m_actors.size()>0)
		{
			for (int i=0;i<m_actors.size();i++)
			{
				m_actors.get(i).Update(dt);
				if (save)
				{
					m_actors.get(i).setPrior();
				}
			}
		}
	}
	
	public Actor Find(short UID)
	{
		if (m_actors.size()>0)
		{
			for (int i=0;i<m_actors.size();i++)
			{
				if (m_actors.get(i).getUID()==UID+1)
				{
					return m_actors.get(i);
				}
			}
		}
		return null;
	}

	@Override
	public void ForceRebuild() {
		// TODO Auto-generated method stub
		
	}
	
}
